package com.xwj.jdk8.stream;

import lombok.AllArgsConstructor;
import lombok.Data;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Comparator;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.Set;
import java.util.stream.Collectors;
import java.util.stream.Stream;

/**
 * @Author: xiaowajiang
 * @Date: 2022-05-04 09:49
 * @Description: Stream流示例
 **/
public class StreamTest {

    public static void main(String[] args) {
        StreamTest test = new StreamTest();
        // test.createStream();
        // test.testFilter();
        // test.testStreamMap();
        // test.testPeek();
        // test.testSorted();
        // test.testMatch();
        // test.testCount();
        // test.testReduce();
        // test.testCollect();
        test.testForEach();
    }

    /**
     * 创建 Stream 流
     */
    public void createStream() {
        // 1. 通过 Collection 集合创建流
        List<String> list = Arrays.asList("A", "B", "C", "D");
        Stream<String> stream = list.stream(); //获取一个顺序流
        Stream<String> parallelStream = list.parallelStream(); //获取一个并行流


        // 2. 通过 Arrays 数组创建流
        Integer[] nums = new Integer[]{1, 2, 3, 4, 5, 6};
        Stream<Integer> streamArr = Arrays.stream(nums);


        // 3. 通过 Stream 的静态方法：of()、iterate()、generate() 创建流
        Stream<Integer> streamOf = Stream.of(1, 2, 3, 4, 5, 6);
        Stream<Integer> streamIterate = Stream.iterate(1, (x) -> x + 2).limit(6);
        Stream<Double> streamGenerate = Stream.generate(Math::random).limit(2);
    }

    /**
     * 中间操作
     */
    // 过滤
    public void testFilter() {
        Stream<String> stream = Stream.of("A", "D", "B", "G", "B", "E", "C", "D");
        stream.filter(s -> !s.equals("A"))
                .distinct() // D B G E C
                .skip(2) // G E C
                .limit(2) // G E
                .forEach(System.out::println);
    }

    // 映射
    public void testStreamMap() {
        Stream<String> stream = Stream.of("a,b,c,d,e,f,g");
        stream.map(i -> i.toUpperCase())
                .flatMap(i -> {
                    // 将每个元素转换成一个 stream
                    String[] split = i.split(",");
                    return Arrays.stream(split);
                })
                .forEach(System.out::println);
    }

    // 消费
    public void testPeek() {
        User u1 = new User("zhangsan", 21);
        User u2 = new User("lisi", 27);
        Stream<User> stream = Stream.of(u1, u2);
        stream.peek(i -> i.setAge(i.getAge() + 1))
                .forEach(System.out::println);
    }

    // 排序
    public void testSorted() {
        Stream<String> stream = Stream.of("A", "D", "F", "B", "G", "E", "C");
        stream.sorted()
                .forEach(System.out::println);

        Stream<User> userStream = Stream.of(new User("A", 21),
                new User("C", 25),
                new User("B", 20));
        userStream.sorted((u1, u2) -> u1.getAge() - u2.getAge())
                .forEach(System.out::println);
    }

    /**
     * 终端操作
     */
    // 匹配操作
    public void testMatch() {
        List<User> list = Arrays.asList(new User("A", 21), new User("C", 25), new User("B", 20));

        boolean b = list.stream().allMatch(i -> i.getAge() > 18);
        System.out.println("allMatch:" + b);

        Optional<User> user = list.stream().filter(i -> i.getAge() > 20)
                .findFirst();
        System.out.println(user.get());
    }

    // 聚合操作
    public void testCount() {
        List<User> list = Arrays.asList(new User("A", 21), new User("C", 25), new User("B", 20));

        long count = list.stream().filter(i -> i.getAge() > 20).count();
        System.out.println("年龄大于20的人数：" + count);

        Optional<User> min = list.stream().filter(i -> i.getAge() > 20)
                .min(Comparator.comparing(User::getAge));
        System.out.println("年龄大于20的人群中最小的：" + min.get());

        Optional<User> max = list.stream().filter(i -> i.getAge() < 25)
                .max(Comparator.comparing(User::getAge));
        System.out.println("年龄小于25的人群中最大的：" + max);
    }

    // 规约
    public void testReduce() {
        // 字符串拼接
        String reduceStr = Stream.of("Xiao", "Wa", "Jiang").reduce("", String::concat);
        System.out.println(reduceStr);

        // 求和，identity(起始值)为0
        Integer total1 = Stream.of(1, 2, 3, 4, 5).reduce(0, Integer::sum);
        // 求和，无起始值
        Integer total2 = Stream.of(1, 2, 3, 4, 5).reduce(Integer::sum).get();
        System.out.println(total1);
        System.out.println(total2);

        // 求最小值
        Integer minValue = Stream.of(1, 8, 10, 6, 2, 3).reduce(Integer.MAX_VALUE, Integer::min);
        System.out.println(minValue);
    }

    // 收集&转换操作
    public void testCollect() {
        List<User> list = Arrays.asList(new User("A", 21), new User("C", 25), new User("B", 20), new User("D", 20));

        // 拼接 name
        String names = list.stream().map(i -> i.getName()).collect(Collectors.joining(","));

        // 转集合
        ArrayList<String> nameArrayList = list.stream().map(i -> i.getName()).collect(Collectors.toCollection(ArrayList::new));
        List<String> nameList = list.stream().map(i -> i.getName()).collect(Collectors.toList());
        Set<String> nameSet = list.stream().map(i -> i.getName()).collect(Collectors.toSet());

        // 转Map
        Map<String, User> userMap = list.stream().collect(Collectors.toMap(User::getName, u -> u, (u1, u2) -> u1));

        // 转数组
        User[] users = list.stream().toArray(User[]::new);

        // 求值（平均值、统计数量、最值、求和）
        Double averaging = list.stream().collect(Collectors.averagingDouble(User::getAge));
        Long count = list.stream().filter(i -> i.getAge() > 20).collect(Collectors.counting());
        User maxUser = list.stream().collect(Collectors.maxBy(Comparator.comparing(User::getAge))).orElse(null);
        User minUser = list.stream().collect(Collectors.minBy(Comparator.comparing(User::getAge))).orElse(null);
        Integer sum = list.stream().collect(Collectors.summingInt(User::getAge));

        // 分组
        Map<Integer, List<User>> listMap = list.stream().collect(Collectors.groupingBy(User::getAge));
        Map<Boolean, List<User>> booleanListMap = list.stream().collect(Collectors.partitioningBy(i -> i.getAge() > 20));

        System.out.println("拼接Name:" + names);
        System.out.println("转集合List:" + nameList.size());
        System.out.println("转集合ArrayList:" + nameArrayList.size());
        System.out.println("转集合Set:" + nameSet.size());
        System.out.println("转集合Map:" + userMap.size());
        System.out.println("转数组:" + users.length);
        System.out.println("平均年龄:" + averaging);
        System.out.println("统计数量(年龄大于20):" + count);
        System.out.println("最大年龄:" + maxUser);
        System.out.println("最小年龄:" + minUser);
        System.out.println("合计年龄:" + sum);
        System.out.println("年龄分组:" + listMap);
        System.out.println("年龄区间分组:" + booleanListMap);
    }

    // 其他操作
    public void testForEach() {
        List<User> list = Arrays.asList(new User("A", 21), new User("C", 25), new User("B", 20), new User("D", 20));
        list.stream().forEach(i -> System.out.println(i));
    }

    @Data
    @AllArgsConstructor
    public static class User {
        private String name;
        private Integer age;
    }

}
